// 让我们一起来玩扫雷游戏！
// 给定一个代表游戏板的二维字符矩阵。 
// 'M' 代表一个未挖出的地雷，
// 'E' 代表一个未挖出的空方块，
// 'B' 代表没有相邻（上，下，左，右，和所有4个对角线）地雷的已挖出的空白方块，
// 数字（'1' 到 '8'）表示有多少地雷与这块已挖出的方块相邻，'X' 则表示一个已挖出的地雷。
// 现在给出在所有未挖出的方块中（'M'或者'E'）的下一个点击位置（行和列索引），
// 根据以下规则，返回相应位置被点击后对应的面板：

//     如果一个地雷（'M'）被挖出，游戏就结束了- 把它改为 'X'。
//     如果一个没有相邻地雷的空方块（'E'）被挖出，修改它为（'B'），并且所有和其相邻的未挖出方块都应该被递归地揭露。
//     如果一个至少与一个地雷相邻的空方块（'E'）被挖出，修改它为数字（'1'到'8'），表示相邻地雷的数量。
//     如果在此次点击中，若无更多方块可被揭露，则返回面板。

// 暴露接口
function updateBoard(board: string[][], click: number[]): string[][] {
  const detact: number[][] = [// 方向向量
    [1, 0],
    [0, 1],
    [-1, 0],
    [0, -1],
    [1, 1],
    [1, -1],
    [-1, 1],
    [-1, -1],
  ];
  let currX: number = click[0];// 取得当前鼠标X坐标
  let currY: number = click[1];// 取得当前鼠标Y坐标
  if (board[currX][currY] === "M") {
    // 挖到地雷直接结束
    board[currX][currY] = "X";
  } else {// 进入广度优先遍历算法流程
    update_BFS(board, currX, currY, detact);
  }
  return board;
}
// 检测数组索引是否越界方法
function checkBound(x: number, y: number, board: string[][]) {
  return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
}
// 广度优先遍历
function update_BFS(board: string[][], x: number, y: number, det: number[][]) {
  const queue = [[x, y]];// 初始化队列为鼠标坐标---> 起点
  while (queue.length > 0) {
    let currCount: number = queue.length; // 记录当前轮次个数
    for (let i = 0; i < currCount; i++) {
      let curr: number[] = queue.shift() as number[]; // 当前元素出队
      let count: number = 0;// 记录当前元素周边的地雷个数
      for (let dire of det) {// 搜索周围坐标
        let newX = curr[0] + dire[0];
        let newY = curr[1] + dire[1];
        if (checkBound(newX, newY, board) && board[newX][newY] === "M") {
          // 计算周围的地雷数量
          count++;
        }
      }
      if (count === 0) {
        // 如果周围没有地雷
        board[curr[0]][curr[1]] = "B"; // 标记当前节点
        for (let dire of det) {
          // 循环入队
          let newX = curr[0] + dire[0];
          let newY = curr[1] + dire[1];
          if (checkBound(newX, newY, board) && board[newX][newY] === "E") {
            // 防止周围的重复入队
            board[newX][newY] = 'B';// 标记成一个其他节点,这个节点后面还会进行地雷数的判断，结果值会覆盖
            queue.push([newX, newY]);
          }
        }
      } else {
        board[curr[0]][curr[1]] = count.toString();// 如果周围存在地雷那就直接计数
      }
    }
  }
}


// 使用广度优先遍历搜索算法求解，具体的过程看代码结合注释。